<?php if ( ! defined('SERVER_ROOT')) exit('No direct script access allowed');
/**
 * MVC Ultra - A ultralight weight MVC framework for PHP
 *
 * MVC ultra is very simple MVC framework that is designed to be easy to use and learn.
 * It does not have all of other frameworks but you add what you need when you need it
 * and understand better whats going on.
 *
 *@author Warren Thomas <wiley_warren@yahoo.com>
 *@copyright Copyright (c) 2012.
 *
 ** 20121027/Warren Thomas      - Created MVC Ultra
 *
 */

/**
 * ultra_mvc is the primary class for Ultra MVC
 *
 * ultra_mvc loads all the primary mvc functions and direct
 * work flow throught the mvc application
 *
 *@package core
 *
 */
class ultra_mvc
{
    /**
     * Holds instance of self to support singleton pattern
     *
     *@access private
     *@property ultra_mvc $instance
     *
     */
    private static $instance = null;

    /**
     * Holds the normalized smart url request in an array
     *
     * @access private
     * @property array $normalized_request
     * 
     */
    private $normalized_request = array();
    
    /**
     * Holds controller object for mvc
     *
     * @access private
     * @property ultra_controller $controller
     * 
     */
    private $controller = null;
    
    /**
     * __construct() - intializes ultra_mvc object and manages mvc workflow
     * 
     *@access public
     *@return void
     *@exception Dump
     * 
     */
    public function __construct(){
        // load helper functions from HELPERS directory
        $this->load_helpers();
        
        // Normalize $_REQUEST to use with smarts urls
        $TMP_REQUEST = $_REQUEST;
        unset($TMP_REQUEST['PHPSESSID']);
        $this->normalized_request = $this->flatten_request( $TMP_REQUEST );
        
        // get controller object
        if(isset($this->normalized_request[0])){
            $controller = array_shift( $this->normalized_request ).'_controller';
        } else {
            $controller = DEFAULT_VIEW.'_controller';
        }
        $this->controller =  new $controller;
        
        // run controller action
        $action = array_shift( $this->normalized_request );
        
        // check static view property exists
        if( property_exists( $controller, 'view' ) ){
            // get format for view
            $format = ultra_view::getFormat($this->normalized_request);
            if( ! $format ) $format = 'html';
            $view = new ultra_view($this->controller->default_view,$format);
            $this->controller->view = $view;
        } else {
            throw new UnexpectedValueException("property 'view' not found for '$controller', make sure class extends ultra_controller");
        }
        
        // check for default action if needed
        if(! isset($this->controller->default_action ) ){
            if( ! isset( $action ) ) $action = $this->controller->default_action;
        } else {
            throw new UnexpectedValueException("property 'default_action' not found for '$controller', make sure class extends ultra_controller");
        }
        
        // execute controller action
        if( method_exists($this->controller,$action)){
            $this->controller->$action($this->normalized_request);
        } else {
            throw new UnexpectedValueException("method '$action' not found for '$controller'");
        }
    }

    /**
     * getInstance() - generates ultra_mvc object and singleton pattern 
     * 
     * @access public
     * @static
     * @return ultra_mvc retrun instance of ultra_mvc
     * 
     */
    public static function getInstance() 
    {
        // if self not instanciated create instance of self
        if( !( self::$instance instanceof ultra_mvc) ) {
            self::$instance = new ultra_mvc();
        }
        // return self
        return self::$instance;
    }

    /**
     * __clone() - disable clone functionality to support singleton pattern
     *
     * @access public
     * @final
     * @return void
     * @exception BadMethodCallException
     */
    public final function __clone()
    {
        throw new BadMethodCallException("Clone is not allowed");
    } 

    /**
     * flatten_request() - coverts a arrays key and values into flat array of values
     *
     * @access private
     * @param array $request key/value array usually the $_REQUEST array
     * @return $array numercally indexed array
     * 
     */
    private function flatten_request($request){
        $flattened = array();
        foreach($request as $key => $value){
            if(isset($key)) {
                if(is_array($key)) continue;
                if($key === "") continue;
                $key = strtr($key,'=','/');
                if(stristr($key,'/')){
                    $value = rtrim($key," /");
                    $arr = explode('/',$key);
                    foreach($arr as $item){
                        $flattened[] = $item;
                    }
                } else {
                    $flattened[] = $key;
                }
            }
            if(isset($value)) {
                if(is_array($value)) continue;
                if($value === "") continue;
                $value = strtr($value,'=','/');
                if(stristr($value,'/')){
                    $value = rtrim($value," /");
                    $arr = explode('/',$value);
                    foreach($arr as $item){
                        $flattened[] = $item;
                    }
                } else {
                    $flattened[] = $value;
                }
            }
        }
        array_shift($flattened);
        return $flattened;
    }

    /**
     * load_helpers() - scans HELPERS directory and load each file found
     *
     * @access private
     * @return void
     * @exception UnexpectedValueException
     */
    private function load_helpers(){
        if (file_exists(HELPERS)){ 
            // Initiate filename array
            $result = $filenames = scandir( HELPERS );
            // include all files in helper directory
            foreach($filenames as $file){
                // The two first $filenames are current and parent directory, let's ignore those
                if ( $file[0] == '.' ) continue;
                include_once( HELPERS .'/'. $file);
            }
        } else {
            //helper directory does not exist!
            throw new UnexpectedValueException("Directy '".HELPERS."' is not found."); 
        }
    }

}